home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / PCX_LIB.ARJ / PCX_DISP.C < prev    next >
C/C++ Source or Header  |  1991-04-07  |  40KB  |  1,141 lines

  1. /*
  2.  *************************************************************************
  3.  *
  4.  *  PCX_DISP.C - PCX_LIB Library Image Display Functions
  5.  *
  6.  *  Version:    1.00B
  7.  *
  8.  *  History:    91/02/14 - Created
  9.  *              91/04/01 - Release 1.00A
  10.  *              91/04/03 - fixed "segread" call.
  11.  *              91/04/07 - Release 1.00B
  12.  *
  13.  *  Compiler:   Microsoft C V6.0
  14.  *
  15.  *  Author:     Ian Ashdown, P.Eng.
  16.  *              byHeart Software
  17.  *              620 Ballantree Road
  18.  *              West Vancouver, B.C.
  19.  *              Canada V7S 1W3
  20.  *              Tel. (604) 922-6148
  21.  *              Fax. (604) 987-7621
  22.  *
  23.  *  Copyright:  Public Domain
  24.  *
  25.  *************************************************************************
  26.  */
  27.  
  28. /*
  29.  *************************************************************************
  30.  *
  31.  *  PORTABILITY NOTES
  32.  *
  33.  *  1.  While this program is written in ANSI C, it uses a number of 
  34.  *      function calls that are specific to the Microsoft C V6.0 library.
  35.  *      These are documented as follows for the purposes of porting this
  36.  *      program to other compilers and/or processors: 
  37.  *
  38.  *          _fmemcpy            - "memcpy" for small model / far data
  39.  *          int86               - execute 80x86 interrupt routine
  40.  *          int86x              - execute 80x86 interrupt routine (far
  41.  *                                data)
  42.  *          _remapallpalette    - remap entire video display color palette
  43.  *          _selectpalette      - select CGA color palette
  44.  *          outpw               - output word to 80x86 I/O port
  45.  *          segread             - get current 80x86 segment register
  46.  *                                values
  47.  *
  48.  *  2.  When porting this program to other processors, remember that words
  49.  *      are stored by 80x86-based machines in the big-endian format.  That
  50.  *      is, the eight least significant bits (lower byte) are stored
  51.  *      first, followed by the eight most significant bits (upper byte).
  52.  *      If PCX-format files are transferred to little-endian machines
  53.  *      (such as those based on 680x0 and Z8000 processors), the order of
  54.  *      bytes within each word will have to be reversed before they can 
  55.  *      be interpreted.  (This applies to the file header only, since the
  56.  *      encoded image data and optional 256-color palette are stored as
  57.  *      bytes.)
  58.  *
  59.  * 3.   MS-DOS does not recognize the 720 x 348 graphics mode of the
  60.  *      Hercules monochrome display adapter.  Therefore, the constant
  61.  *      PCX_HERC should never be passed as a video mode parameter to any
  62.  *      BIOS service routine.
  63.  *
  64.  *      The Microsoft C compiler includes a "video mode" parameter
  65.  *      definition (_HERCMONO) that is defined as 0x08.  This is a
  66.  *      reserved MS-DOS video mode that is apparently used internally by
  67.  *      the ROM BIOS.  It can, however, be passed to the Microsoft C
  68.  *      library function "_setvideomode" to force the Hercules display
  69.  *      adapter into graphics mode.
  70.  *
  71.  *      Most other MS-DOS C compilers offer similar library functions to
  72.  *      force the Hercules monochrome display adapter into its 720 x 348
  73.  *      graphics mode.
  74.  *
  75.  ************************************************************************* 
  76.  */
  77.  
  78. /*      INCLUDE FILES                                                   */
  79.  
  80. #include <stdio.h>
  81. #include <stdlib.h>
  82. #include <string.h>
  83. #include <conio.h>
  84. #include <dos.h>
  85. #include <malloc.h>
  86. #include <graph.h>
  87. #include "pcx_int.h"
  88.  
  89. /*      FORWARD REFERENCES                                              */
  90.  
  91. static BOOL pcx_read_init(PCX_WORKBLK *, int, int);
  92. static BOOL pcx_read_extpal(PCX_WORKBLK *);
  93. static BOOL pcx_read_header(PCX_WORKBLK *);
  94. static BOOL pcx_read_line(PCX_WORKBLK *, unsigned char *, int);
  95. static BOOL pcx_set_palette(PCX_PAL *, int);
  96.  
  97. static void pcx_cga_palette(PCX_PAL *, int);
  98. static void pcx_put_cga(PCX_WORKBLK *, unsigned char _far *, int);
  99. static void pcx_put_ega(PCX_WORKBLK *, unsigned char _far *, int);
  100. static void pcx_put_herc(PCX_WORKBLK *, unsigned char _far *, int);
  101. static void pcx_put_vga(PCX_WORKBLK *, unsigned char _far *, int);
  102.  
  103. /*      GLOBALS                                                         */
  104.  
  105. /*      PUBLIC FUNCTIONS                                                */
  106.  
  107. /*
  108.  *************************************************************************
  109.  *
  110.  *  PCX_READ - Read PCX Image File
  111.  *
  112.  *  Purpose:    To read and display a PCX-format image file.
  113.  *
  114.  *  Setup:      BOOL pcx_read
  115.  *              (
  116.  *                char *fname,
  117.  *                int vmode,
  118.  *                int page
  119.  *              )
  120.  *
  121.  *  Where:      fname is a PCX image file name.
  122.  *              vmode is the MS-DOS video mode.  Valid values are:
  123.  *
  124.  *                PCX_HERC -    720 x 348 Hercules monochrome
  125.  *                0x04 -        320 x 200 4-color CGA
  126.  *                0x05 -        320 x 200 4-color CGA (color burst off)
  127.  *                0x06 -        640 x 200 2-color CGA
  128.  *                0x0d -        320 x 200 16-color EGA/VGA
  129.  *                0x0e -        640 x 200 16-color EGA/VGA
  130.  *                0x0f -        640 x 350 2-color EGA/VGA
  131.  *                0x10 -        640 x 350 16-color EGA/VGA
  132.  *                0x11 -        640 x 480 2-color VGA
  133.  *                0x12 -        640 x 480 16-color VGA
  134.  *                0x13 -        320 x 200 256-color VGA
  135.  *
  136.  *              page is the video display page number.  Valid values are:
  137.  *
  138.  *                Mode PCX_HERC - 0 or 1
  139.  *                Mode 0x0d     - 0 to 7
  140.  *                Mode 0x0e     - 0 to 3
  141.  *                Mode 0x0f     - 0 or 1
  142.  *                Mode 0x10     - 0 or 1
  143.  *                All Other     - 0
  144.  *
  145.  *  Return:     TRUE if successful; otherwise FALSE.
  146.  *
  147.  *  Note:       The video display adapter must be in the appropriate mode
  148.  *              and active page for the image to be displayed.
  149.  *
  150.  *************************************************************************
  151.  */
  152.  
  153. BOOL pcx_read
  154. (
  155.   char *fname,
  156.   int vmode,
  157.   int page
  158. )
  159. {
  160.   int bpline;                   /* Number of bytes per scan line        */
  161.   int line_num;                 /* Scan line number                     */
  162.   int max_lines;                /* Maximum number of scan lines         */
  163.   unsigned char *linep;         /* PCX scan line buffer pointer         */
  164.   BOOL status = TRUE;           /* Return status                        */
  165.   PCX_WORKBLK *wbp;             /* PCX image file workblock pointer     */
  166.  
  167.   /* Open a PCX image file workblock                                    */
  168.  
  169.   if ((wbp = pcx_open(fname, FALSE)) == (PCX_WORKBLK *) NULL)
  170.     return (FALSE);
  171.  
  172.   /* Initialize the workblock for reading                               */
  173.  
  174.   if (pcx_read_init(wbp, vmode, page) == FALSE)
  175.   {
  176.     (void) pcx_close(wbp);      /* Close the PCX workblock              */
  177.     return (FALSE);
  178.   }
  179.  
  180.   /* Calculate the image height                                         */
  181.  
  182.   max_lines = wbp->header.yul + wbp->header.ylr + 1;
  183.  
  184.   /* Calculate number of bytes per line (for all color planes)          */
  185.  
  186.   bpline = wbp->header.bppscan * wbp->header.nplanes;
  187.  
  188.   /* Allocate the PCX scan line buffer                                  */
  189.  
  190.   if ((linep = (unsigned char *) malloc(bpline)) != (unsigned char *)
  191.       NULL)
  192.   {
  193.     /* Set the file pointer to the beginning of the encoded image data  */
  194.  
  195.     if (status == TRUE)
  196.       if (fseek(wbp->fp, (long) (sizeof(PCX_HDR)), SEEK_SET) != 0)
  197.         status = FALSE;
  198.  
  199.     /* Set the video display adapter color palette unless the PCX file  */
  200.     /* is Version 3.0 (i.e. - PC Paintbrush Version 2.8 w/o palette)    */
  201.  
  202.     if (status == TRUE)
  203.       if (wbp->header.version != 3)
  204.         if (pcx_set_palette(wbp->palettep, vmode) == FALSE)
  205.           status = FALSE;
  206.  
  207.     /* Read the image line by line                                      */
  208.  
  209.     if (status == TRUE)
  210.     {
  211.       for (line_num = 0; line_num < max_lines; line_num++)
  212.       {
  213.         /* Read the current scan line                                   */
  214.  
  215.         if ((status = pcx_read_line(wbp, linep, bpline)) == FALSE)
  216.         {
  217.           status = FALSE;
  218.           break;
  219.         }
  220.  
  221.         /* Display the current scan line                                */
  222.  
  223.         wbp->pcx_funcp(wbp, (unsigned char _far *) linep, line_num);
  224.       }
  225.     }
  226.  
  227.     free(linep);        /* Free the PCX scan line buffer                */
  228.   }
  229.   else
  230.     status = FALSE;
  231.                          
  232.   if (pcx_close(wbp) == FALSE)  /* Close the PCX workblock              */
  233.     status = FALSE;
  234.  
  235.   return (status);
  236. }
  237.  
  238. /*      PRIVATE FUNCTIONS                                               */
  239.  
  240. /*
  241.  *************************************************************************
  242.  *
  243.  *  PCX_READ_INIT - Initialize PCX Workblock For Reading
  244.  *
  245.  *  Purpose:    To initialize a PCX image file workblock for reading.
  246.  *
  247.  *  Setup:      static BOOL pcx_read_init
  248.  *              (
  249.  *                PCX_WORKBLK *wbp,
  250.  *                int vmode,
  251.  *                int page
  252.  *              )
  253.  *
  254.  *  Where:      wbp is a PCX workblock pointer.
  255.  *              vmode is the MS-DOS video mode.  Valid values are:
  256.  *
  257.  *                PCX_HERC -    720 x 348 Hercules monochrome
  258.  *                0x04 -        320 x 200 4-color CGA
  259.  *                0x05 -        320 x 200 4-color CGA (color burst off)
  260.  *                0x06 -        640 x 200 2-color CGA
  261.  *                0x0d -        320 x 200 16-color EGA/VGA
  262.  *                0x0e -        640 x 200 16-color EGA/VGA
  263.  *                0x0f -        640 x 350 2-color EGA/VGA
  264.  *                0x10 -        640 x 350 16-color EGA/VGA
  265.  *                0x11 -        640 x 480 2-color VGA
  266.  *                0x12 -        640 x 480 16-color VGA
  267.  *                0x13 -        320 x 200 256-color VGA
  268.  *
  269.  *              page is the video display page number.  Valid values are:
  270.  *
  271.  *                Mode PCX_HERC - 0 or 1
  272.  *                Mode 0x0d     - 0 to 7
  273.  *                Mode 0x0e     - 0 to 3
  274.  *                Mode 0x0f     - 0 or 1
  275.  *                Mode 0x10     - 0 or 1
  276.  *                All Other      - 0
  277.  *
  278.  *  Return:     TRUE if successful; otherwise FALSE.
  279.  *
  280.  *************************************************************************
  281.  */
  282.  
  283. static BOOL pcx_read_init
  284. (
  285.   PCX_WORKBLK *wbp,
  286.   int vmode,
  287.   int page
  288. )
  289. {
  290.   int width;                    /* Display width                        */
  291.   int leftover;                 /* Number of unseen bits                */
  292.   BOOL status = TRUE;           /* Return status                        */
  293.  
  294.   /* Read the file header                                               */
  295.  
  296.   if ((pcx_read_header(wbp)) == FALSE)
  297.     return (FALSE);
  298.  
  299.   /* Initialize the workblock color palette pointer                     */
  300.  
  301.   wbp->palettep = wbp->header.palette;
  302.   wbp->epal_flag = FALSE;
  303.  
  304.   /* Read the extended palette (if any)                                 */
  305.  
  306.   if (vmode == 0x13 && wbp->header.version == 5)
  307.     if (pcx_read_extpal(wbp) == FALSE)
  308.       return (FALSE);
  309.  
  310.   /* Initialize the display page address offset                         */
  311.  
  312.   wbp->page_offset = (unsigned long) 0L;
  313.  
  314.   switch (vmode)        /* Select PCX line display function             */
  315.   {
  316.     case PCX_HERC:      /* 720 x 348 Hercules monochrome                */
  317.  
  318.       /* Hercules monochrome display adapter supports 2 pages           */
  319.  
  320.       wbp->page_offset = 0x08000000L * (unsigned long) page;
  321.  
  322.       /* Calculate display width in pixels                              */
  323.  
  324.       width = min((wbp->header.xlr - wbp->header.xul + 1), 720);
  325.  
  326.       /* Calculate number of bytes to display                           */
  327.  
  328.       wbp->num_bytes = (width + 7) >> 3;
  329.  
  330.       /* Calculate mask for leftover bits                               */
  331.  
  332.       if ((leftover = width & 7) != 0)
  333.         wbp->mask = (0xff << (8 - leftover)) & 0xff;
  334.       else
  335.         wbp->mask = 0xff;
  336.  
  337.       wbp->pcx_funcp = pcx_put_herc;    /* Set the display function ptr */
  338.  
  339.       break;
  340.  
  341.     case 0x04:          /* 320 x 200 4-color CGA                        */
  342.     case 0x05:          /* 320 x 200 4-color CGA (color burst off)      */
  343.   
  344.       /* Calculate display width in pixels                              */
  345.  
  346.       width = min((wbp->header.xlr - wbp->header.xul + 1), 320);
  347.  
  348.       /* Calculate number of bytes to display                           */
  349.  
  350.       wbp->num_bytes = (width + 3) >> 2;
  351.  
  352.       /* Calculate mask for leftover bits                               */
  353.  
  354.       if ((leftover = (width & 3) << 1) != 0)
  355.         wbp->mask = (0xff << (8 - leftover)) & 0xff;
  356.       else
  357.         wbp->mask = 0xff;
  358.  
  359.       wbp->pcx_funcp = pcx_put_cga;     /* Set the display function ptr */
  360.  
  361.       break;
  362.  
  363.     case 0x06:          /* 640 x 200 2-color CGA                        */
  364.  
  365.       /* Calculate display width in pixels                              */
  366.  
  367.       width = min((wbp->header.xlr - wbp->header.xul + 1), 640);
  368.  
  369.       /* Calculate number of bytes to display                           */
  370.  
  371.       wbp->num_bytes = (width + 7) >> 3;
  372.  
  373.       /* Calculate mask for leftover bits                               */
  374.  
  375.       if ((leftover = width & 7) != 0)
  376.         wbp->mask = (0xff << (8 - leftover)) & 0xff;
  377.       else
  378.         wbp->mask = 0xff;
  379.  
  380.       wbp->pcx_funcp = pcx_put_cga;     /* Set the display function ptr */
  381.  
  382.       break;
  383.  
  384.     case 0x0d:          /* 320 x 200 16-color EGA/VGA                   */
  385.     case 0x0e:          /* 640 x 200 16-color EGA/VGA                   */
  386.     case 0x0f:          /* 640 x 350 2-color EGA/VGA                    */
  387.     case 0x10:          /* 640 x 350 16-color EGA/VGA                   */
  388.     case 0x11:          /* 640 x 480 2-color VGA                        */
  389.     case 0x12:          /* 640 x 480 16-color VGA                       */
  390.  
  391.       switch (vmode)    /* Initialize the display adapter page offset   */
  392.       {
  393.         case 0x0d:      /* 320 x 200 16-color EGA/VGA (8 pages maximum) */
  394.  
  395.           wbp->page_offset = 0x02000000L * (unsigned long) page;
  396.  
  397.           break;
  398.  
  399.         case 0x0e:      /* 640 x 200 16-color EGA/VGA (4 pages maximum) */
  400.  
  401.           wbp->page_offset = 0x04000000L * (unsigned long) page;
  402.  
  403.           break;
  404.  
  405.         case 0x0f:      /* 640 x 350 2-color EGA/VGA (2 pages maximum)  */
  406.         case 0x10:      /* 640 x 350 16-color EGA/VGA (2 pages maximum) */
  407.  
  408.           wbp->page_offset = 0x08000000L * (unsigned long) page;
  409.  
  410.           break;
  411.  
  412.         default:        /* All other modes support only one page        */
  413.  
  414.           break;
  415.       }
  416.  
  417.       /* Calculate display width in pixels                              */
  418.  
  419.       width = min((wbp->header.xlr - wbp->header.xul + 1), 640);
  420.  
  421.       /* Calculate number of bytes to display                           */
  422.  
  423.       wbp->num_bytes = (width + 7) >> 3;
  424.  
  425.       /* Calculate mask for leftover bits                               */
  426.  
  427.       if ((leftover = width & 7) != 0)
  428.         wbp->mask = (0xff << (8 - leftover)) & 0xff;
  429.       else
  430.         wbp->mask = 0xff;
  431.  
  432.       wbp->pcx_funcp = pcx_put_ega;     /* Set the display function ptr */
  433.  
  434.       break;
  435.  
  436.     case 0x13:          /* 320 x 200 256-color VGA                      */
  437.  
  438.       /* Calculate number of bytes to display                           */
  439.  
  440.       wbp->num_bytes = min((wbp->header.xlr - wbp->header.xul + 1), 320);
  441.  
  442.       wbp->mask = 0;  /* Dummy parameter                                */
  443.  
  444.       wbp->pcx_funcp = pcx_put_vga;     /* Set the display function ptr */
  445.  
  446.       break;
  447.  
  448.     default:            /* Other display adapters not supported         */
  449.  
  450.       status = FALSE;
  451.  
  452.       break;
  453.   }
  454.  
  455.   return (status);
  456. }
  457.  
  458. /*
  459.  *************************************************************************
  460.  *
  461.  *  PCX_READ_HEADER - Read PCX File Header
  462.  *
  463.  *  Purpose:    To read and validate a PCX file header.
  464.  *
  465.  *  Setup:      static BOOL pcx_read_header
  466.  *              (
  467.  *                PCX_WORKBLK *wbp
  468.  *              )
  469.  *
  470.  *  Where:      wbp is a PCX image file workblock pointer.
  471.  *
  472.  *  Return:     TRUE if successful; otherwise FALSE.
  473.  *
  474.  *  Result:     The file header is read into the "header" member of the
  475.  *              PCX workblock.
  476.  *
  477.  *************************************************************************
  478.  */
  479.  
  480. static BOOL pcx_read_header
  481. (
  482.   PCX_WORKBLK *wbp
  483. )
  484. {
  485.   BOOL status = TRUE;   /* Status flag                                  */
  486.   PCX_HDR *hdrp;        /* PCX file header buffer pointer               */
  487.  
  488.   hdrp = &(wbp->header);        /* Initialize the file header pointer   */
  489.  
  490.   /* Read the file header                                               */
  491.  
  492.   if (fseek(wbp->fp, 0L, SEEK_SET) != 0)
  493.     status = FALSE;
  494.  
  495.   if (status == TRUE)
  496.     if (fread(hdrp, sizeof(PCX_HDR), 1, wbp->fp) != 1)
  497.       status = FALSE;
  498.  
  499.   /* Validate the PCX file format                                       */
  500.  
  501.   if (status == TRUE)
  502.     if ((hdrp->pcx_id != 0x0a) || (hdrp->encoding != 1))
  503.       status = FALSE;
  504.  
  505.   return (status);
  506. }
  507.  
  508. /*
  509.  *************************************************************************
  510.  *
  511.  *  PCX_READ_EXTPAL - Read Extended Palette
  512.  *
  513.  *  Purpose:    To read an extended (256-color) palette (if it exists).
  514.  *
  515.  *  Setup:      static BOOL pcx_read_extpal
  516.  *              (
  517.  *                PCX_WORKBLK *wbp
  518.  *              )
  519.  *
  520.  *  Where:      wbp is a PCX image file workblock pointer.
  521.  *
  522.  *  Return:     TRUE if successful; otherwise FALSE.
  523.  *
  524.  *  Note:       It is possible for a PCX image file without an appended
  525.  *              256-color palette to have the value 0x0c as the 769th byte
  526.  *              (the location of the extended palette indicator byte) from 
  527.  *              the end of the file (i.e. - in the encoded image data 
  528.  *              section).  This function will misinterpret the following
  529.  *              768 bytes of encoded image data as an extended palette.
  530.  *
  531.  *              This problem will only occur if an attempt is made to
  532.  *              display a PCX image using the wrong MS-DOS video mode.  It
  533.  *              can be detected by decoding the image data and using 
  534.  *              "ftell" to note the file position of the end of the 
  535.  *              encoded image data section, then comparing it to the file
  536.  *              position of the indicator byte.  If the supposed indicator
  537.  *              byte is located within the encoded image data section, the
  538.  *              indicator byte is invalid and so the file header palette
  539.  *              should be used instead.
  540.  *
  541.  *************************************************************************
  542.  */
  543.  
  544. static BOOL pcx_read_extpal
  545. (
  546.   PCX_WORKBLK *wbp
  547. )
  548. {
  549.   int indicator;        /* PCX extended palette indicator               */
  550.  
  551.   /* Position the file pointer to the extended palette indicator byte   */
  552.  
  553.   if (fseek(wbp->fp, -769L, SEEK_END) != 0)
  554.     return (FALSE);
  555.  
  556.   /* Read the (assumed) extended palette indicator byte                 */
  557.  
  558.   if ((indicator = getc(wbp->fp)) == EOF)
  559.     return (FALSE);
  560.  
  561.   if (indicator == PCX_EPAL_FLAG)       /* Check for indicator byte     */
  562.   {
  563.     /* Allocate an extended palette buffer                              */
  564.  
  565.     if ((wbp->palettep = (PCX_PAL *) calloc(sizeof(PCX_PAL),
  566.         PCX_EPAL_SIZE)) == (PCX_PAL *) NULL)
  567.       return (FALSE);
  568.  
  569.     /* Read the extended palette                                        */
  570.  
  571.     if (fread(wbp->palettep, sizeof(PCX_PAL), PCX_EPAL_SIZE, wbp->fp) !=
  572.         PCX_EPAL_SIZE)
  573.     {
  574.       free(wbp->palettep);      /* Free the extended palette buffer     */
  575.       return (FALSE);
  576.     }
  577.  
  578.     wbp->epal_flag = TRUE;      /* Indicate extended palette present    */
  579.   }
  580.  
  581.   return (TRUE);
  582. }
  583.  
  584. /*
  585.  *************************************************************************
  586.  *
  587.  *  PCX_READ_LINE - Read PCX Line
  588.  *
  589.  *  Purpose:    To read an encoded line (all color planes) from a PCX-
  590.  *              format image file and write the decoded data to a line
  591.  *              buffer.
  592.  *
  593.  *  Setup:      static BOOL pcx_read_line
  594.  *              (
  595.  *                PCX_WORKBLK *wbp,
  596.  *                unsigned char *linep,
  597.  *                int bpline
  598.  *              )
  599.  *
  600.  *  Where:      wbp is a PCX image file workblock pointer.
  601.  *              linep is a PCX scan line buffer pointer.
  602.  *              bpline is the number of bytes per scan line (all color
  603.  *                planes).
  604.  *
  605.  *  Return:     TRUE if successful; otherwise FALSE.
  606.  *
  607.  *************************************************************************
  608.  */
  609.  
  610. static BOOL pcx_read_line
  611. (
  612.   PCX_WORKBLK *wbp,
  613.   unsigned char *linep,
  614.   int bpline
  615. )
  616. {
  617.   int data;             /* Image data byte                              */
  618.   int count;            /* Image data byte repeat count                 */
  619.   int offset = 0;       /* Scan line buffer offset                      */
  620.  
  621.   while (offset < bpline)       /* Decode current scan line             */
  622.   {
  623.     if ((data = getc(wbp->fp)) == EOF)  /* Get next byte                */
  624.       return (FALSE);
  625.  
  626.     /* If top two bits of byte are set, lower six bits show how         */
  627.     /* many times to duplicate next byte                                */
  628.  
  629.     if ((data & PCX_COMP_FLAG) == PCX_COMP_FLAG)
  630.     {
  631.       count = data & PCX_COMP_MASK;     /* Mask off repeat count        */
  632.  
  633.       if ((data = getc(wbp->fp)) == EOF)        /* Get next byte        */
  634.         return (FALSE);
  635.  
  636.       memset(linep, data, count);       /* Duplicate byte               */
  637.       linep += count;
  638.       offset += count;
  639.     }
  640.     else
  641.     {
  642.       *linep++ = (unsigned char) data;  /* Copy byte                    */
  643.       offset++;
  644.     }
  645.   }
  646.  
  647.   return (TRUE);
  648. }
  649.  
  650. /*
  651.  *************************************************************************
  652.  *
  653.  *  PCX_SET_PALETTE - Set Palette
  654.  *
  655.  *  Purpose:    To set the display palette according to a PCX file
  656.  *              palette.
  657.  *
  658.  *  Setup:      static BOOL pcx_set_palette
  659.  *              (
  660.  *                PCX_PAL *palettep,
  661.  *                int vmode
  662.  *              )
  663.  *
  664.  *  Where:      palettep is a pointer to a PCX file palette.
  665.  *              vmode is the MS-DOS video mode.  Valid values are:
  666.  *
  667.  *                PCX_HERC -    720 x 348 Hercules monochrome
  668.  *                0x04 -        320 x 200 4-color CGA
  669.  *                0x05 -        320 x 200 4-color CGA (color burst off)
  670.  *                0x06 -        640 x 200 2-color CGA
  671.  *                0x0d -        320 x 200 16-color EGA/VGA
  672.  *                0x0e -        640 x 200 16-color EGA/VGA
  673.  *                0x0f -        640 x 350 2-color EGA/VGA
  674.  *                0x10 -        640 x 350 16-color EGA/VGA
  675.  *                0x11 -        640 x 480 2-color VGA
  676.  *                0x12 -        640 x 480 16-color VGA
  677.  *                0x13 -        320 x 200 256-color VGA
  678.  *
  679.  *  Return:     TRUE if successful; otherwise FALSE.
  680.  *
  681.  *************************************************************************
  682.  */
  683.  
  684. static BOOL pcx_set_palette
  685. (
  686.   PCX_PAL *palettep,
  687.   int vmode
  688. )
  689. {
  690.   int i;                        /* Scratch counter                      */
  691.   int red_lo;                   /* Low red intensity                    */
  692.   int red_hi;                   /* High red intensity                   */
  693.   int green_lo;                 /* Green low intensity                  */
  694.   int green_hi;                 /* Green high intensity                 */
  695.   int blue_lo;                  /* Blue low intensity                   */
  696.   int blue_hi;                  /* Blue high intensity                  */
  697.   unsigned char *ega_palp;      /* EGA 16-color palette buffer pointer  */
  698.   unsigned long *vga_palp;      /* VGA 256-color palette buffer pointer */
  699.   BOOL status = TRUE;           /* Return status                        */
  700.   union REGS regs;              /* 80x86 register values                */
  701.   struct SREGS sregs;           /* 80x86 segment register values        */
  702.  
  703.   switch (vmode)
  704.   {
  705.     case PCX_HERC:      /* 720 x 348 Hercules monochrome                */
  706.  
  707.       break;
  708.  
  709.     case 0x04:          /* 320 x 200 4-color CGA display                */
  710.     case 0x05:          /* 320 x 200 monochrome CGA display (burst off) */
  711.     case 0x06:          /* 640 x 200 2-color CGA display                */
  712.  
  713.       /* Set the CGA color palette                                      */
  714.  
  715.       pcx_cga_palette(palettep, vmode);
  716.  
  717.       break;
  718.  
  719.     case 0x0d:          /* 320 x 200 16-color EGA/VGA                   */
  720.     case 0x0e:          /* 640 x 200 16-color EGA/VGA                   */
  721.     case 0x0f:          /* 640 x 350 2-color EGA/VGA                    */
  722.     case 0x10:          /* 640 x 350 16-color EGA/VGA                   */
  723.     case 0x11:          /* 640 x 480 2-color VGA                        */
  724.     case 0x12:          /* 640 x 480 16-color VGA                       */
  725.  
  726.       if (pcx_isvga() == TRUE)  /* Check for VGA display adapter        */
  727.       {
  728.         /* Allocate a 16-color VGA display adapter palette buffer       */
  729.  
  730.         if ((vga_palp = (unsigned long *) calloc(sizeof(unsigned long),
  731.             PCX_PAL_SIZE)) == (unsigned long *) NULL)
  732.         {
  733.           status = FALSE;
  734.           break;
  735.         }
  736.  
  737.         /* Map PCX hardware palette to 16-color VGA palette (each color */
  738.         /* value is a "long" with the form:                             */
  739.         /*                                                              */
  740.         /*      00000000-00BBBBBB-00GGGGGG-00RRRRRR                     */
  741.         /*                                                              */
  742.         /* where each color is a 6-bit value.                           */
  743.  
  744.         for (i = 0; i < PCX_PAL_SIZE; i++)
  745.           vga_palp[i] = (long) (palettep[i].red >> 2) |
  746.               ((long) (palettep[i].green >> 2)) << 8 |
  747.               ((long) (palettep[i].blue >> 2)) << 16;
  748.  
  749.         (void) _remapallpalette(vga_palp);      /* Remap entire palette */
  750.  
  751.         free(vga_palp);         /* Free the VGA palette buffer          */
  752.       }
  753.       else      /* EGA display adapter                                  */
  754.       {
  755.         /* Allocate an EGA display adapter palette buffer               */
  756.  
  757.         if ((ega_palp = (unsigned char *) calloc(sizeof(unsigned char),
  758.             PCX_PAL_SIZE + 1)) == (unsigned char *) NULL)
  759.         {
  760.           status = FALSE;
  761.           break;
  762.         }
  763.  
  764.         /* Map PCX hardware palette to 16-color EGA palette (each EGA   */
  765.         /* color value is an "unsigned char" with the form:             */
  766.         /*                                                              */
  767.         /*        0  0  R' G' B' R  G  B                                */
  768.         /*                                                              */
  769.         /* where X' is the low-intensity value and X is the high        */
  770.         /* intensity value for the color X.)                            */
  771.         /*                                                              */
  772.         /* NOTE: the "_remapallpalette" function could be used to set   */
  773.         /*       the palette for EGA display adapters.  However, this   */
  774.         /*       function does not appear to update the palette         */
  775.         /*       register values in the Dynamic Save Area (see the      */
  776.         /*       function header for "pcx_init_palette" in PCX_FILE.C)  */
  777.         /*       for a detailed explanation).                           */
  778.  
  779.         for (i = 0; i < PCX_PAL_SIZE; i++)
  780.         {
  781.           /* Extract low and high intensity bits for each color         */
  782.  
  783.           red_lo = (palettep[i].red >> 6) & 0x01;
  784.           red_hi = (palettep[i].red >> 6) & 0x02;
  785.           green_lo = (palettep[i].green >> 6) & 0x01;
  786.           green_hi = (palettep[i].green >> 6) & 0x02;
  787.           blue_lo = (palettep[i].blue >> 6) & 0x01;
  788.           blue_hi = (palettep[i].blue >> 6) & 0x02;
  789.  
  790.           /* Combine color intensity bits for EGA palette value         */
  791.  
  792.           ega_palp[i] = (unsigned char) ((red_lo << 5) | (green_lo << 4) |
  793.               (blue_lo << 3) | (red_hi << 1) | green_hi | (blue_hi >>
  794.               1));
  795.         }
  796.  
  797.         /* Set the border (overscan) color to black (BIOS default)      */
  798.  
  799.         ega_palp[16] = (unsigned char) 0;
  800.  
  801.         regs.h.ah = 0x10;       /* Select "Set All Palette Registers"   */
  802.         regs.h.al = 0x02;
  803.  
  804.         /* Get the EGA palette registers buffer offset value            */
  805.  
  806.         regs.x.dx = (unsigned int) ega_palp;
  807.  
  808.         segread(&sregs);  /* Get the current DS segment register value  */
  809.  
  810.         sregs.es = sregs.ds;
  811.  
  812.         int86x(0x10, ®s, ®s, &sregs);  /* Call BIOS video service */
  813.  
  814.         free(ega_palp);         /* Free the EGA palette buffer          */
  815.       }
  816.  
  817.       break;
  818.  
  819.     case 0x13:          /* 320 x 200 256-color VGA display              */
  820.  
  821.       /* Allocate a 256-color VGA display adapter palette buffer        */
  822.  
  823.       if ((vga_palp = (unsigned long *) calloc(sizeof(unsigned long),
  824.           PCX_EPAL_SIZE)) == (unsigned long *) NULL)
  825.       {
  826.         status = FALSE;
  827.         break;
  828.       }
  829.  
  830.       /* Map PCX extended palette to 256-color VGA palette              */
  831.  
  832.       for (i = 0; i < PCX_EPAL_SIZE; i++)
  833.         vga_palp[i] = (long) (palettep[i].red >> 2) |
  834.             ((long) (palettep[i].green >> 2)) << 8 |
  835.             ((long) (palettep[i].blue >> 2)) << 16;
  836.  
  837.       (void) _remapallpalette(vga_palp);        /* Remap entire palette */
  838.  
  839.       free(vga_palp);   /* Free the VGA palette buffer                  */
  840.  
  841.       break;
  842.  
  843.     default:            /* Other modes not supported                    */
  844.  
  845.       status = FALSE;
  846.  
  847.       break;
  848.   }
  849.  
  850.   return (status);
  851. }
  852.  
  853. /*
  854.  *************************************************************************
  855.  *
  856.  *  PCX_CGA_PALETTE - Select CGA Palette
  857.  *
  858.  *  Purpose:    To set the Color Graphics Adapter (CGA) display palette
  859.  *              according to a PCX file palette.
  860.  *
  861.  *  Setup:      static void pcx_cga_palette
  862.  *              (
  863.  *                PCX_PAL *palettep,
  864.  *                int vmode
  865.  *              )
  866.  *
  867.  *  Where:      palettep is a pointer to a PCX file palette.
  868.  *              vmode is the MS-DOS video mode.  Valid values are:
  869.  *
  870.  *                0x04 -        320 x 200 4-color CGA
  871.  *                0x05 -        320 x 200 4-color CGA (color burst off)
  872.  *                0x06 -        640 x 200 2-color CGA
  873.  *
  874.  *  Note:       ZSoft's PC Paintbrush products no longer support the CGA
  875.  *              color palette.  When a CGA color palette is encountered,
  876.  *              PC Paintbrush maps it to a monochrome (black and white)
  877.  *              palette.
  878.  *
  879.  *              MS-DOS video mode 0x05 (320 x 200 monochrome CGA display,
  880.  *              color burst off) will only display a monochrome image on
  881.  *              a composite video monitor (typically a television set with
  882.  *              an RF adapter).  All other monitors will display a color
  883.  *              palette in this mode (which is different for CGA and EGA
  884.  *              or VGA display adapters).
  885.  *
  886.  *              The "background" color is actually the foreground color
  887.  *              (i.e. - the color of activated pixels) for MS-DOS video
  888.  *              mode 0x06.  The background color is black for CGA display
  889.  *              adapters.
  890.  *
  891.  *************************************************************************
  892.  */
  893.  
  894. static void pcx_cga_palette
  895. (
  896.   PCX_PAL *palettep,
  897.   int vmode
  898. )
  899. {
  900.   short pal_num;        /* Palette number                               */
  901.   BOOL sel_flag;        /* Palette selector bit flag                    */
  902.   BOOL int_flag;        /* Intensity bit flag                           */
  903.   union REGS regs;      /* 80x86 register values                        */
  904.  
  905.   /* Set the background color                                           */
  906.  
  907.   regs.h.ah = 0x0b;     /* Select "Set Color Palette" BIOS routine      */
  908.   regs.h.bh = 0;
  909.  
  910.   regs.h.bl = (unsigned char) PCX_CGA_BKGND(palettep);
  911.  
  912.   int86(0x10, ®s, ®s);    /* Call BIOS video service              */
  913.  
  914.   if (vmode != 0x06)    /* Select the CGA color palette                 */
  915.   {
  916.     /* Check the palette selector bit flag                              */
  917.  
  918.     sel_flag = PCX_CGA_SELECT(palettep) ? TRUE : FALSE;
  919.  
  920.     /* Check the intensity bit flag                                     */
  921.  
  922.     int_flag = PCX_CGA_INTENSITY(palettep) ? TRUE : FALSE;
  923.  
  924.     /* Determine the CGA palette number                                 */
  925.  
  926.     if (int_flag == TRUE)       /* Intensity = bright                   */
  927.     {
  928.       if (sel_flag == TRUE)
  929.         pal_num = 3;    /* Light cyan - light magenta - white           */
  930.       else
  931.         pal_num = 1;    /* Cyan - magenta - light grey                  */
  932.     }
  933.     else                        /* Intensity = dim                      */
  934.     {
  935.       if (sel_flag == TRUE)
  936.         pal_num = 2;    /* Light green - light red - yellow             */
  937.       else
  938.         pal_num = 0;    /* Green - red - brown                          */
  939.     }
  940.  
  941.     /* Select the foreground color palette                              */
  942.  
  943.     (void) _selectpalette(pal_num);
  944.   }
  945. }
  946.  
  947. /*
  948.  *************************************************************************
  949.  *
  950.  *  PCX_PUT_HERC - Display Hercules PCX Line
  951.  *
  952.  *  Purpose:    To copy a decoded PCX image scan line to a Hercules
  953.  *              monochrome graphics display adapter buffer.
  954.  *
  955.  *  Setup:      static void pcx_put_herc
  956.  *              (
  957.  *                PCX_WORKBLK *wbp,
  958.  *                unsigned char _far *linep,
  959.  *                int line_num
  960.  *              )
  961.  *
  962.  *  Where:      wbp is a PCX image file workblock pointer.
  963.  *              linep is a PCX scan line buffer pointer.
  964.  *              line_num is the scan line number.
  965.  *
  966.  *************************************************************************
  967.  */
  968.  
  969. void pcx_put_herc
  970. (
  971.   PCX_WORKBLK *wbp,
  972.   unsigned char _far *linep,
  973.   int line_num
  974. )
  975. {
  976.   unsigned char _far *displayp;         /* Display buffer pointer       */
  977.  
  978.   /* Mask off unseen pixels                                             */
  979.  
  980.   linep[wbp->num_bytes - 1] &= wbp->mask;
  981.  
  982.   /* Calculate Hercules display buffer pointer                          */
  983.  
  984.   displayp = (unsigned char _far *) (0xb0000000L + wbp->page_offset) +
  985.       ((line_num >> 2) * 90) + 0x2000 * (line_num & 3);
  986.  
  987.   /* Copy data from the scan line buffer to the Hercules display buffer */
  988.  
  989.   (void) _fmemcpy(displayp, linep, wbp->num_bytes);
  990. }
  991.  
  992. /*
  993.  *************************************************************************
  994.  *
  995.  *  PCX_PUT_CGA - Display CGA PCX Line
  996.  *
  997.  *  Purpose:    To copy a decoded PCX image scan line to a CGA display
  998.  *              adapter buffer.
  999.  *
  1000.  *  Setup:      static void pcx_put_cga
  1001.  *              (
  1002.  *                PCX_WORKBLK *wbp,
  1003.  *                unsigned char _far *linep,
  1004.  *                int line_num
  1005.  *              )
  1006.  *
  1007.  *  Where:      wbp is a PCX image file workblock pointer.
  1008.  *              linep is a PCX scan line buffer pointer.
  1009.  *              line_num is the scan line number.
  1010.  *
  1011.  *************************************************************************
  1012.  */
  1013.  
  1014. static void pcx_put_cga
  1015. (
  1016.   PCX_WORKBLK *wbp,
  1017.   unsigned char _far *linep,
  1018.   int line_num
  1019. )
  1020. {
  1021.   unsigned char _far *displayp;         /* Display buffer pointer       */
  1022.  
  1023.   /* Mask off unseen pixels                                             */
  1024.  
  1025.   linep[wbp->num_bytes - 1] &= wbp->mask;
  1026.  
  1027.   /* Calculate CGA display buffer pointer                               */
  1028.  
  1029.   displayp = (unsigned char _far *) 0xb8000000L + ((line_num >> 1) * 80)
  1030.       + 0x2000 * (line_num & 1);
  1031.  
  1032.   /* Copy data from the scan line buffer to the CGA display buffer      */
  1033.  
  1034.   (void) _fmemcpy(displayp, linep, wbp->num_bytes);
  1035. }
  1036.  
  1037. /*
  1038.  *************************************************************************
  1039.  *
  1040.  *  PCX_PUT_EGA - Display EGA/VGA PCX Line
  1041.  *
  1042.  *  Purpose:    To copy a decoded PCX image scan line to an EGA/VGA
  1043.  *              display adapter buffer.
  1044.  *
  1045.  *  Setup:      static void pcx_put_ega
  1046.  *              (
  1047.  *                PCX_WORKBLK *wbp,
  1048.  *                unsigned char _far *linep,
  1049.  *                int line_num
  1050.  *              )
  1051.  *
  1052.  *  Where:      wbp is a PCX image file workblock pointer.
  1053.  *              linep is a PCX scan line buffer pointer.
  1054.  *              line_num is the scan line number.
  1055.  *
  1056.  *************************************************************************
  1057.  */
  1058.  
  1059. static void pcx_put_ega
  1060. (
  1061.   PCX_WORKBLK *wbp,
  1062.   unsigned char _far *linep,
  1063.   int line_num
  1064. )
  1065. {
  1066.   int plane_num;                /* EGA/VGA color plane number           */
  1067.   int plane_mask;               /* EGA/VGA color plane mask             */
  1068.   unsigned char _far *displayp; /* Display buffer pointer               */
  1069.  
  1070.   /* Calculate buffer pointer                                           */
  1071.  
  1072.   displayp = (unsigned char _far *) (0xa0000000L + wbp->page_offset) +
  1073.       line_num * 80;
  1074.  
  1075.   outpw(0x03ce, 0x0005);        /* Select EGA/VGA write mode 0          */
  1076.  
  1077.   /* Copy PCX scan line data to each color plane                        */
  1078.  
  1079.   plane_mask = 0x0100;          /* Start with color plane 0             */
  1080.  
  1081.   for (plane_num = 0; plane_num < (int) wbp->header.nplanes; plane_num++)
  1082.   {
  1083.     /* Mask off unseen pixels                                           */
  1084.  
  1085.     linep[wbp->num_bytes - 1] &= wbp->mask;
  1086.  
  1087.     outpw(0x03c4, plane_mask + 2);      /* Select current color plane   */
  1088.  
  1089.     /* Copy data from the scan line buffer to the EGA/VGA display       */
  1090.  
  1091.     (void) _fmemcpy(displayp, linep, wbp->num_bytes);
  1092.  
  1093.     linep += wbp->header.bppscan;       /* Increment plane offset       */
  1094.  
  1095.     plane_mask <<= 1;   /* Sequence plane mask                          */
  1096.   }
  1097.  
  1098.   outpw(0x03c4, 0x0f02);        /* Select all color planes              */
  1099. }
  1100.  
  1101. /*
  1102.  *************************************************************************
  1103.  *
  1104.  *  PCX_PUT_VGA - Display VGA PCX Line
  1105.  *
  1106.  *  Purpose:    To copy a decoded PCX image scan line to a VGA display
  1107.  *              adapter buffer.
  1108.  *
  1109.  *  Setup:      static void pcx_put_vga
  1110.  *              (
  1111.  *                PCX_WORKBLK *wbp,
  1112.  *                unsigned char _far *linep,
  1113.  *                int line_num
  1114.  *              )
  1115.  *
  1116.  *  Where:      wbp is a PCX image file workblock pointer.
  1117.  *              linep is a PCX scan line buffer pointer.
  1118.  *              line_num is the scan line number.
  1119.  *
  1120.  *************************************************************************
  1121.  */
  1122.  
  1123. static void pcx_put_vga
  1124. (
  1125.   PCX_WORKBLK *wbp,
  1126.   unsigned char _far *linep,
  1127.   int line_num
  1128. )
  1129. {
  1130.   unsigned char _far *displayp;         /* Display buffer pointer       */
  1131.  
  1132.   /* Calculate buffer pointer                                           */
  1133.  
  1134.   displayp = (unsigned char _far *) 0xa0000000L + line_num * 320;
  1135.  
  1136.   /* Copy data from the scan line buffer to the VGA display buffer      */
  1137.  
  1138.   (void) _fmemcpy(displayp, linep, wbp->num_bytes);
  1139. }
  1140.  
  1141.